1 Introduction

This RMarkdown document is part of the Generic Skills Component (GSK) of the Course of the Foundation Studies Programme at Srishti Manipal Institute of Art, Design, and Technology, Bangalore India. The material is based on A Layered Grammar of Graphics by Hadley Wickham. The course is meant for First Year students pursuing a Degree in Art and Design.

The intent of this GSK part is to build Skill in coding in R, and also appreciate R as a way to metaphorically visualize information of various kinds, using predominantly geometric figures and structures.

All RMarkdown files combine code, text, web-images, and figures developed using code. Everything is text; code chunks are enclosed in fences (```)

2 Goals

At the end of this Lab session, we should: - know the types and structures of spatial data and be able to work with them - understand the basics of modern spatial packages in R - be able to specify and download spatial data from the web, using R from sources such as naturalearth and Open Streep Map - plot static and interactive maps using ggplot, tmap and leaflet packages - add symbols and markers for places and regions of our own interest in these maps. - see directions for further work (e.g. maps + networks together)

3 Pedagogical Note

The method followed will be based on PRIMM:

  • PREDICT Inspect the code and guess at what the code might do, write predictions
  • RUN the code provided and check what happens
  • INFER what the parameters of the code do and write comments to explain. What bells and whistles can you see?
  • MODIFY the parameters code provided to understand the options available. Write comments to show what you have aimed for and achieved.
  • MAKE : take an idea/concept of your own, and graph it.

3.1 Set Up

The setup code chunk below brings into our coding session R packages that provide specific computational abilities and also datasets which we can use.

To reiterate: Packages and datasets are not the same thing !! Packages are (small) collections of programs. Datasets are just….information.

5 Introduction to Maps in R

We will take small steps in making maps using just two of the several map making packages in R.

The steps we will use are:

  1. Search for an area of interest ( E.g. using prettymapr or similar..)
  2. Learn how to access spatial/map data using osmdata
  3. Plot and dress up our map using osmplot, tmap and also with leaflet.
  4. Create interactive maps with leaflet using a variety of map data providers. Note: tmap can also do interactive maps which we will explore also.

Bas. Onwards and Map-wards!!

All jargon words will be capitalized and in bold font.

6 God made me a BengaluR-kaR…I think

Let’s get BLR data into R and see if we can plot an area of interest. Then we can order on Swiggy and…never mind.

  1. Where is my home? Specify a “BOUNDING BOX” first, using a rough longitude latitude info directly, or using a place name to search for the long/lat info:
# BLR Bounding Box
# get_bbox needs lat and lon ranges
bbox <- osmplotr::get_bbox(c(77.56,12.93,77.63,12.96))

bbox_l <- osmdata::getbb("Bangalore, India") # LARGE
bbox_p <- prettymapr::searchbbox("Bangalore") # ALSO LARGE
## Using default API key for pickpoint.io. If batch geocoding, please get your own (free) API key at https://app.pickpoint.io/sign-up
bbox
##     min   max
## x 77.56 77.63
## y 12.93 12.96
bbox_l
##        min      max
## x 77.46010 77.78405
## y 12.83401 13.14366
bbox_p # identical with bbox_l
##        min      max
## x 77.46010 77.78405
## y 12.83401 13.14366

We will use the smaller bbox from the above, to ensure we have smaller data downloads!

Within our bbox for BLR, we want to download diverse kinds of FEATURE data. Remember that a FEATURE This is done using the osmplotr::extract_osm_objects() command. The main parameters for this command are:

  • bbox
  • KEY / VALUE pairs (“TAGS”) to specify the kind of feature you need

See OSM Tags for a nice visual description of popular tags that we can use. Useful keys include: - building : yes (all), house residential, apartments - highway: residential, service, track, unclassified, footway, path - amenity: parking, parking_space, bench; place_of_worship; restaurant, cafe, fast_food; school, waste_basket, fuel, bank, toilets… - shop: convenience, supermarket, clothes, hairdresser, car-repair… - name: actual name of the place e.g. Main_Street, McDonald’s, Pizza Hut, Subway - waterway - natural, - boundary - highway*.

For example see: tag : highway

# Get Map data

dat_B <- extract_osm_objects (key = "building", bbox = bbox) 
dat_H <- extract_osm_objects (key = 'highway', bbox = bbox)
dat_P <- extract_osm_objects (key = 'park', bbox = bbox)
dat_G <- extract_osm_objects (key = 'landuse', value = 'grass', bbox = bbox)
dat_T <- extract_osm_objects (key = 'natural', value = 'tree', bbox = bbox)

6.1 Let’s look at the data

# How many buildings?
nrow(dat_B)
## [1] 39699
dat_B$geometry
## Geometry set for 39699 features 
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 77.55967 ymin: 12.92885 xmax: 77.63028 ymax: 12.96168
## Geodetic CRS:  WGS 84
## First 5 geometries:
## POLYGON ((77.58405 12.93005, 77.5845 12.93005, ...
## POLYGON ((77.58647 12.94997, 77.58645 12.94994,...
## POLYGON ((77.61162 12.9368, 77.61159 12.93667, ...
## POLYGON ((77.61255 12.93615, 77.61251 12.93601,...
## POLYGON ((77.61291 12.93646, 77.61276 12.93594,...
class(dat_B$geometry)
## [1] "sfc_POLYGON" "sfc"

So dat_B has 39699 buildings and their geometry is naturally a POLYGON type of geometry column.

6.2 Your Turn 1

Do this check for all the other spatial data, in the code chunk below.

What kind of geometry column does each dataset have?

6.3 What Other Kinds of Data could we get from OSM?

osm_structures returns a data.frame of OSM structure types, associated key-value pairs, unique suffices which may be appended to data structures for storage purposes, and suggested colours.

osm_structures()
##     structure      key value suffix      cols
## 1    building building           BU #646464FF
## 2     amenity  amenity            A #787878FF
## 3    waterway waterway            W #646478FF
## 4       grass  landuse grass      G #64A064FF
## 5     natural  natural            N #647864FF
## 6        park  leisure  park      P #647864FF
## 7     highway  highway            H #000000FF
## 8    boundary boundary           BO #C8C8C8FF
## 9        tree  natural  tree      T #64A064FF
## 10 background                          gray20

6.4 My first Map in R

We could quickly plot this using the package osmplotr. However, in my ( i.e. Arvind’s opinion ) it is not as flexible as other packages. Maybe I need to study it in more detail.

So we will continue with ggplot and geom_sf() :

blr_map <- ggplot() +
  geom_sf(data = dat_B, colour = "orange") +  # POLYGONS
  geom_sf(data = dat_H, col = "gray20") +     # LINES
  geom_sf(data = dat_G, col = "darkseagreen1") + 
  geom_sf(data = dat_P, col = "darkseagreen") +
  geom_sf(data = dat_T, col = "green")        # POINTS
blr_map

Note how geom_sf is capable of handling any geometry in the sfc column !!

geom_sf() is an unusual geom because it will draw different geometric objects depending on what simple features are present in the data: you can get points, lines, or polygons.

So there, we have our first map!

7 Using rnaturalearth and tmap

Let’s plot a first map using datasets built into tmap. Then we can download other datasets from rnaturalearth and plot them next.

tmap has a few built-in spatial datasets: World and metro, rivers, land and a few others. Check help on these.

data("World")
head(World, n = 3)
## Simple feature collection with 3 features and 15 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 11.6401 ymin: -17.93064 xmax: 75.15803 ymax: 42.68825
## Geodetic CRS:  WGS 84
##   iso_a3        name  sovereignt continent           area  pop_est pop_est_dens
## 1    AFG Afghanistan Afghanistan      Asia  652860 [km^2] 28400000     43.50090
## 2    AGO      Angola      Angola    Africa 1246700 [km^2] 12799293     10.26654
## 3    ALB     Albania     Albania    Europe   27400 [km^2]  3639453    132.82675
##                     economy             income_grp gdp_cap_est life_exp
## 1 7. Least developed region          5. Low income    784.1549   59.668
## 2 7. Least developed region 3. Upper middle income   8617.6635       NA
## 3      6. Developing region 4. Lower middle income   5992.6588   77.347
##   well_being footprint inequality      HPI                       geometry
## 1        3.8      0.79  0.4265574 20.22535 MULTIPOLYGON (((61.21082 35...
## 2         NA        NA         NA       NA MULTIPOLYGON (((16.32653 -5...
## 3        5.5      2.21  0.1651337 36.76687 MULTIPOLYGON (((20.59025 41...

We have several 14 attribute variables in World. Attribute variables such as gdp_cap_est, HPI are numeric. Others such as income_grp appear to be factors. iso_a3 is the standard three letter name for the country.

data("metro")
head(metro, n = 3)
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## Simple feature collection with 3 features and 12 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: 3.04197 ymin: -8.83682 xmax: 69.17246 ymax: 36.7525
## Geodetic CRS:  WGS 84
##       name             name_long iso_a3 pop1950 pop1960 pop1970 pop1980 pop1990
## 2    Kabul                 Kabul    AFG  170784  285352  471891  977824 1549320
## 8  Algiers El Djazair  (Algiers)    DZA  516450  871636 1281127 1621442 1797068
## 13  Luanda                Luanda    AGO  138413  219427  459225  771349 1390240
##    pop2000 pop2010 pop2020  pop2030                  geometry
## 2  2401109 3722320 5721697  8279607 POINT (69.17246 34.52889)
## 8  2140577 2432023 2835218  3404575   POINT (3.04197 36.7525)
## 13 2591388 4508434 6836849 10428756 POINT (13.23432 -8.83682)

Here too we have attribute variables for the metros, and they seem predominantly numeric. Again iso_a3 is the three letter name for the city.

tmap plots are made with code in “groups”: each group starts with a tm_shape() command.

tmap_mode("plot") # Making this a static plot
## tmap mode set to plotting
# Group 1
tm_shape(World) + # dataset = World. 
    tm_polygons("HPI") + # Colour polygons by HPI numeric variable

  # Note the "+" sign continuation
  
# Group 2
tm_shape(metro) + # dataset = metro
  tm_bubbles(size = "pop2020", 
             col = "red") 
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()

# Plot cities as bubbles
# Size proportional to numeric variable `pop2020`
tmap_mode("view") # Change to Interactive
## tmap mode set to interactive viewing
tm_shape(World) +
    tm_polygons("HPI") +
  
  
tm_shape(metro) + 
  tm_bubbles(size = "pop2020", 
             col = "red") +

# Let's use WaterColor Map this time!!
tm_tiles("Stamen.TonerLabels")
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## Legend for symbol sizes not available in view mode.

7.1 Using data from rnaturalearth

india <- 
  ne_states(country =  "india", 
            geounit = "india", 
            returnclass = "sf")

india_neighbours <- 
  ne_states(country = (c("india", "sri lanka", "pakistan",
                         "afghanistan", "nepal","bangladesh")
                       ),
            returnclass = "sf")

Let’s look at the attribute variable columns to colour our graph and to shape our symbols:

names(india)
##  [1] "featurecla" "scalerank"  "adm1_code"  "diss_me"    "iso_3166_2"
##  [6] "wikipedia"  "iso_a2"     "adm0_sr"    "name"       "name_alt"  
## [11] "name_local" "type"       "type_en"    "code_local" "code_hasc" 
## [16] "note"       "hasc_maybe" "region"     "region_cod" "provnum_ne"
## [21] "gadm_level" "check_me"   "datarank"   "abbrev"     "postal"    
## [26] "area_sqkm"  "sameascity" "labelrank"  "name_len"   "mapcolor9" 
## [31] "mapcolor13" "fips"       "fips_alt"   "woe_id"     "woe_label" 
## [36] "woe_name"   "latitude"   "longitude"  "sov_a3"     "adm0_a3"   
## [41] "adm0_label" "admin"      "geonunit"   "gu_a3"      "gn_id"     
## [46] "gn_name"    "gns_id"     "gns_name"   "gn_level"   "gn_region" 
## [51] "gn_a1_code" "region_sub" "sub_code"   "gns_level"  "gns_lang"  
## [56] "gns_adm1"   "gns_region" "min_label"  "max_label"  "min_zoom"  
## [61] "wikidataid" "name_ar"    "name_bn"    "name_de"    "name_en"   
## [66] "name_es"    "name_fr"    "name_el"    "name_hi"    "name_hu"   
## [71] "name_id"    "name_it"    "name_ja"    "name_ko"    "name_nl"   
## [76] "name_pl"    "name_pt"    "name_ru"    "name_sv"    "name_tr"   
## [81] "name_vi"    "name_zh"    "ne_id"      "geometry"
names(india_neighbours)
##  [1] "featurecla" "scalerank"  "adm1_code"  "diss_me"    "iso_3166_2"
##  [6] "wikipedia"  "iso_a2"     "adm0_sr"    "name"       "name_alt"  
## [11] "name_local" "type"       "type_en"    "code_local" "code_hasc" 
## [16] "note"       "hasc_maybe" "region"     "region_cod" "provnum_ne"
## [21] "gadm_level" "check_me"   "datarank"   "abbrev"     "postal"    
## [26] "area_sqkm"  "sameascity" "labelrank"  "name_len"   "mapcolor9" 
## [31] "mapcolor13" "fips"       "fips_alt"   "woe_id"     "woe_label" 
## [36] "woe_name"   "latitude"   "longitude"  "sov_a3"     "adm0_a3"   
## [41] "adm0_label" "admin"      "geonunit"   "gu_a3"      "gn_id"     
## [46] "gn_name"    "gns_id"     "gns_name"   "gn_level"   "gn_region" 
## [51] "gn_a1_code" "region_sub" "sub_code"   "gns_level"  "gns_lang"  
## [56] "gns_adm1"   "gns_region" "min_label"  "max_label"  "min_zoom"  
## [61] "wikidataid" "name_ar"    "name_bn"    "name_de"    "name_en"   
## [66] "name_es"    "name_fr"    "name_el"    "name_hi"    "name_hu"   
## [71] "name_id"    "name_it"    "name_ja"    "name_ko"    "name_nl"   
## [76] "name_pl"    "name_pt"    "name_ru"    "name_sv"    "name_tr"   
## [81] "name_vi"    "name_zh"    "ne_id"      "geometry"
# Look only at attributes
india %>% st_drop_geometry() %>% head()
##             featurecla scalerank adm1_code diss_me iso_3166_2 wikipedia iso_a2
## 3   Admin-1 scale rank         2  IND-3264    3264      IN-GJ      <NA>     IN
## 16  Admin-1 scale rank         2  IND-2431    2431      IN-JK      <NA>     IN
## 47  Admin-1 scale rank         2  IND-3299    3299      IN-AR      <NA>     IN
## 576 Admin-1 scale rank         2  IND-2477    2477      IN-AS      <NA>     IN
## 578 Admin-1 scale rank         2  IND-3259    3259      IN-SK      <NA>     IN
## 581 Admin-1 scale rank         2  IND-3257    3257      IN-WB      <NA>     IN
##     adm0_sr              name
## 3         1           Gujarat
## 16        1 Jammu and Kashmir
## 47        1 Arunachal Pradesh
## 576       1             Assam
## 578       1            Sikkim
## 581       4       West Bengal
##                                                                           name_alt
## 3                                                                             <NA>
## 16                                                                            <NA>
## 47  Agence de la Frontisre du Nord-Est(French-obsolete)|North East Frontier Agency
## 576                                                                           <NA>
## 578                                                                           <NA>
## 581                Bangla|Bengala Occidentale|Bengala Ocidental|Bengale occidental
##     name_local  type type_en code_local code_hasc note hasc_maybe    region
## 3         <NA>  <NA>    <NA>       <NA>     IN.GJ <NA>       <NA>      West
## 16        <NA> State   State       <NA>     IN.JK <NA>       <NA>     North
## 47        <NA> State   State       <NA>     IN.AR <NA>       <NA> Northeast
## 576       <NA> State   State       <NA>     IN.AS <NA>       <NA> Northeast
## 578       <NA> State   State       <NA>     IN.SK <NA>       <NA>      East
## 581       <NA> State   State       <NA>     IN.WB <NA>       <NA>      East
##     region_cod provnum_ne gadm_level check_me datarank abbrev postal area_sqkm
## 3         <NA>      20064          1       20        1   <NA>   <NA>         0
## 16        <NA>      20066          1       20        1   <NA>     JK         0
## 47        <NA>      20045          1       20        1   <NA>     AR         0
## 576       <NA>      20049          1       20        1   <NA>     AS         0
## 578       <NA>      20058          1       20        1   <NA>     SK         0
## 581       <NA>      20010          1       20        1   <NA>     WB         0
##     sameascity labelrank name_len mapcolor9 mapcolor13 fips fips_alt  woe_id
## 3           NA         2        7         2          2 IN32     <NA> 2345743
## 16          NA         2       17         2          2 IN12     <NA> 2345746
## 47          NA         2       17         2          2 IN30     <NA> 2345763
## 576         NA         2        5         2          2 IN03     <NA> 2345741
## 578         NA         2        6         2          2 IN29     <NA> 2345762
## 581         NA         2       11         2          2 IN28     <NA> 2345761
##                        woe_label          woe_name latitude longitude sov_a3
## 3             Gujarat, IN, India           Gujarat  22.7501   71.3013    IND
## 16  Jammu and Kashmir, IN, India Jammu and Kashmir  33.9658   76.6395    IND
## 47  Arunachal Pradesh, IN, India Arunachal Pradesh  28.4056   94.4673    IND
## 576             Assam, IN, India             Assam  26.3302   92.9929    IND
## 578            Sikkim, IN, India            Sikkim  27.5709   88.4482    IND
## 581       West Bengal, IN, India       West Bengal  23.0523   87.7289    IND
##     adm0_a3 adm0_label admin geonunit gu_a3   gn_id                    gn_name
## 3       IND          2 India    India   IND 1270770           State of Gujarat
## 16      IND          5 India    India   IND 1269320 State of Jammu and Kashmir
## 47      IND          5 India    India   IND 1278341 State of Arunachal Pradesh
## 576     IND          2 India    India   IND 1278253             State of Assam
## 578     IND          2 India    India   IND 1256312            State of Sikkim
## 581     IND          2 India    India   IND 1252881       State of West Bengal
##       gns_id                    gns_name gn_level gn_region gn_a1_code
## 3   -2096768           Gujarat, State of        1      <NA>      IN.09
## 16  -2098229 Jammu and Kashmir, State of        1      <NA>      IN.12
## 47  -2089163 Arunachal Pradesh, State of        1      <NA>      IN.30
## 576 -2089251             Assam, State of        1      <NA>      IN.03
## 578 -2111292            Sikkim, State of        1      <NA>      IN.29
## 581 -2114741       West Bengal, State of        1      <NA>      IN.28
##     region_sub sub_code gns_level gns_lang gns_adm1 gns_region min_label
## 3         <NA>     <NA>         1      nld     IN09       <NA>       4.6
## 16        <NA>     <NA>         1      nld     IN12       <NA>       4.6
## 47        <NA>     <NA>         1      nld     IN30       <NA>       4.6
## 576       <NA>     <NA>         1      nld     IN03       <NA>       4.6
## 578       <NA>     <NA>         1      nld     IN29       <NA>       4.6
## 581       <NA>     <NA>         1      nld     IN28       <NA>       4.6
##     max_label min_zoom wikidataid name_ar name_bn           name_de
## 3        10.1      4.6      Q1061    <NA>    <NA>           Gujarat
## 16       10.1      4.6      Q1180    <NA>    <NA> Jammu und Kashmir
## 47       10.1      4.6      Q1162    <NA>    <NA> Arunachal Pradesh
## 576      10.1      4.6      Q1164    <NA>    <NA>             Assam
## 578      10.1      4.6      Q1505    <NA>    <NA>            Sikkim
## 581      10.1      4.6      Q1356    <NA>    <NA>      Westbengalen
##               name_en            name_es            name_fr name_el name_hi
## 3             Gujarat            Guyarat            Gujarat    <NA>    <NA>
## 16  Jammu and Kashmir  Jammu y Cachemira Jammu-et-Cachemire    <NA>    <NA>
## 47  Arunachal Pradesh  Arunachal Pradesh  Arunachal Pradesh    <NA>    <NA>
## 576             Assam              Assam              Assam    <NA>    <NA>
## 578            Sikkim             Sikkim             Sikkim    <NA>    <NA>
## 581       West Bengal Bengala Occidental Bengale-Occidental    <NA>    <NA>
##               name_hu           name_id             name_it name_ja name_ko
## 3           Gudzsarát           Gujarat             Gujarat    <NA>    <NA>
## 16  Dzsammu és Kasmír Jammu dan Kashmir     Jammu e Kashmir    <NA>    <NA>
## 47   Arunácsal Prades Arunachal Pradesh   Arunachal Pradesh    <NA>    <NA>
## 576            Asszám             Assam               Assam    <NA>    <NA>
## 578           Szikkim            Sikkim              Sikkim    <NA>    <NA>
## 581     Nyugat-Bengál    Benggala Barat Bengala Occidentale    <NA>    <NA>
##               name_nl           name_pl           name_pt name_ru
## 3             Gujarat          Gudzarat          Gujarate    <NA>
## 16   Jammu en Kasjmir  Dzammu i Kaszmir  Jammu e Caxemira    <NA>
## 47  Arunachal Pradesh Arunachal Pradesh Arunachal Pradesh    <NA>
## 576             Assam              Asam             Assam    <NA>
## 578            Sikkim            Sikkim            Siquim    <NA>
## 581     West-Bengalen   Bengal Zachodni Bengala Ocidental    <NA>
##               name_sv           name_tr           name_vi name_zh      ne_id
## 3             Gujarat           Gucerat           Gujarat    <NA> 1159314179
## 16  Jammu och Kashmir   Cemmu ve Kesmir  Jammu và Kashmir    <NA> 1159311911
## 47  Arunachal Pradesh Arunaçhal Pradesh Arunachal Pradesh    <NA> 1159315223
## 576             Assam             Assam             Assam    <NA> 1159311865
## 578            Sikkim            Sikkim            Sikkim    <NA> 1159314169
## 581      Västbengalen       Bati Bengal        Tây Bengal    <NA> 1159313981
india_neighbours%>% st_drop_geometry() %>% head()
##            featurecla scalerank adm1_code diss_me iso_3166_2 wikipedia iso_a2
## 2  Admin-1 scale rank         3  PAK-1114    1114      PK-SD      <NA>     PK
## 3  Admin-1 scale rank         2  IND-3264    3264      IN-GJ      <NA>     IN
## 16 Admin-1 scale rank         2  IND-2431    2431      IN-JK      <NA>     IN
## 38 Admin-1 scale rank         3  PAK-1111    1111      PK-GB      <NA>     PK
## 39 Admin-1 scale rank         3  PAK-1109    1109      PK-JK      <NA>     PK
## 40 Admin-1 scale rank         3  PAK-1113    1113      PK-PB      <NA>     PK
##    adm0_sr              name       name_alt name_local
## 2        1              Sind          Sindh       <NA>
## 3        1           Gujarat           <NA>       <NA>
## 16       1 Jammu and Kashmir           <NA>       <NA>
## 38       1    Northern Areas           <NA>       <NA>
## 39       1      Azad Kashmir        Kashmir       <NA>
## 40       1            Punjab Pendjab|Penjab       <NA>
##                           type                     type_en code_local code_hasc
## 2                     Province                    Province       <NA>     PK.SD
## 3                         <NA>                        <NA>       <NA>     IN.GJ
## 16                       State                       State       <NA>     IN.JK
## 38 Centrally Administered Area Centrally Administered Area       <NA>     PK.NA
## 39 Centrally Administered Area Centrally Administered Area       <NA>     PK.JK
## 40                    Province                    Province       <NA>     PK.PB
##                                                        note    hasc_maybe
## 2                                                      <NA>          <NA>
## 3                                                      <NA>          <NA>
## 16                                                     <NA>          <NA>
## 38                                                     <NA>          <NA>
## 39 Should be divided into 8 districts. Check with Wikipedia          <NA>
## 40                                                     <NA> PK.IS|PAK-PNJ
##    region region_cod provnum_ne gadm_level check_me datarank abbrev postal
## 2    <NA>       <NA>          2          1       20        2   <NA>     SD
## 3    West       <NA>      20064          1       20        1   <NA>   <NA>
## 16  North       <NA>      20066          1       20        1   <NA>     JK
## 38   <NA>       <NA>          4          1       20        2   <NA>     NA
## 39   <NA>       <NA>          3          1       20        2   <NA>     JK
## 40   <NA>       <NA>          5          1       20        2   <NA>     PB
##    area_sqkm sameascity labelrank name_len mapcolor9 mapcolor13 fips fips_alt
## 2          0         NA         3        4         3         11 PK05     <NA>
## 3          0         NA         2        7         2          2 IN32     <NA>
## 16         0         NA         2       17         2          2 IN12     <NA>
## 38         0         NA         3       14         3         11 PK07     <NA>
## 39         0         NA         3       12         3         11 PK06     <NA>
## 40         0         NA         3        6         3         11 PK04     PK08
##     woe_id                    woe_label          woe_name latitude longitude
## 2  2346499          Sindh, PK, Pakistan              Sind  26.3734   68.8685
## 3  2345743           Gujarat, IN, India           Gujarat  22.7501   71.3013
## 16 2345746 Jammu and Kashmir, IN, India Jammu and Kashmir  33.9658   76.6395
## 38 2346501 Northern Areas, PK, Pakistan    Northern Areas  35.7864   74.9848
## 39 2346500   Azad Kashmir, PK, Pakistan      Azad Kashmir  33.8680   73.8036
## 40 2346498         Punjab, PK, Pakistan            Punjab  31.3589   72.3449
##    sov_a3 adm0_a3 adm0_label    admin geonunit gu_a3   gn_id
## 2     PAK     PAK          2 Pakistan Pakistan   PAK 1164807
## 3     IND     IND          2    India    India   IND 1270770
## 16    IND     IND          5    India    India   IND 1269320
## 38    PAK     PAK          5 Pakistan Pakistan   PAK 1168878
## 39    PAK     PAK          5 Pakistan Pakistan   PAK 1184196
## 40    PAK     PAK          2 Pakistan Pakistan   PAK 1167710
##                       gn_name   gns_id                    gns_name gn_level
## 2                       Sindh -2774813                       Sindh        1
## 3            State of Gujarat -2096768           Gujarat, State of        1
## 16 State of Jammu and Kashmir -2098229 Jammu and Kashmir, State of        1
## 38             Northern Areas        0                        <NA>        1
## 39               Azad Kashmir        0                        <NA>        1
## 40                     Punjab -2771862                      Punjab        1
##    gn_region gn_a1_code region_sub sub_code gns_level gns_lang gns_adm1
## 2       <NA>      PK.05       <NA>     <NA>         1      rus     PK05
## 3       <NA>      IN.09       <NA>     <NA>         1      nld     IN09
## 16      <NA>      IN.12       <NA>     <NA>         1      nld     IN12
## 38      <NA>      PK.07       <NA>     <NA>         0     <NA>     <NA>
## 39      <NA>      PK.06       <NA>     <NA>         0     <NA>     <NA>
## 40      <NA>      PK.04       <NA>     <NA>         1      eng     PK04
##    gns_region min_label max_label min_zoom wikidataid name_ar name_bn
## 2        <NA>       5.0      10.5      5.0     Q37211    <NA>    <NA>
## 3        <NA>       4.6      10.1      4.6      Q1061    <NA>    <NA>
## 16       <NA>       4.6      10.1      4.6      Q1180    <NA>    <NA>
## 38       <NA>       5.0      10.5      5.0    Q200697    <NA>    <NA>
## 39       <NA>       5.0      10.5      5.0    Q200130    <NA>    <NA>
## 40       <NA>       5.0      10.5      5.0      Q4478    <NA>    <NA>
##                    name_de           name_en           name_es
## 2                    Sindh             Sindh             Sindh
## 3                  Gujarat           Gujarat           Guyarat
## 16       Jammu und Kashmir Jammu and Kashmir Jammu y Cachemira
## 38        Gilgit-Baltistan  Gilgit-Baltistan  Gilgit-Baltistán
## 39 Asad Jammu und Kaschmir      Azad Kashmir    Azad Cachemira
## 40                  Punjab            Punjab            Panyab
##               name_fr name_el name_hi           name_hu           name_id
## 2                Sind    <NA>    <NA>            Szindh             Sindh
## 3             Gujarat    <NA>    <NA>         Gudzsarát           Gujarat
## 16 Jammu-et-Cachemire    <NA>    <NA> Dzsammu és Kasmír Jammu dan Kashmir
## 38   Gilgit-Baltistan    <NA>    <NA>              <NA>  Gilgit–Baltistan
## 39     Azad Cachemire    <NA>    <NA>              <NA>      Azad Kashmir
## 40            Pendjab    <NA>    <NA>          Pandzsáb            Punjab
##             name_it name_ja name_ko          name_nl               name_pl
## 2             Sindh    <NA>    <NA>            Sindh                 Sindh
## 3           Gujarat    <NA>    <NA>          Gujarat              Gudzarat
## 16  Jammu e Kashmir    <NA>    <NA> Jammu en Kasjmir      Dzammu i Kaszmir
## 38 Gilgit-Baltistan    <NA>    <NA> Gilgit-Baltistan      Gilgit-Baltistan
## 39     Azad Kashmir    <NA>    <NA>     Azad Kasjmir Azad Dzammu i Kaszmir
## 40           Punjab    <NA>    <NA>           Punjab               Pendzab
##             name_pt name_ru           name_sv          name_tr          name_vi
## 2              Sind    <NA>             Sindh     Sind Eyaleti            Sindh
## 3          Gujarate    <NA>           Gujarat          Gucerat          Gujarat
## 16 Jammu e Caxemira    <NA> Jammu och Kashmir  Cemmu ve Kesmir Jammu và Kashmir
## 38 Gilgit-Baltistão    <NA>  Gilgit-Baltistan Gilgit-Baltistan Gilgit-Baltistan
## 39   Caxemira Livre    <NA>      Azad Kashmir      Azad Kesmir     Azad Kashmir
## 40           Punjab    <NA>            Punjab   Pencap Eyaleti           Punjab
##    name_zh      ne_id
## 2     <NA> 1159309351
## 3     <NA> 1159314179
## 16    <NA> 1159311911
## 38    <NA> 1159310545
## 39    <NA> 1159310503
## 40    <NA> 1159309349

7.2 Map 1

tmap_mode("view")
## tmap mode set to interactive viewing
# Plot the Neighbours
tm_shape(World %>% dplyr::filter(iso_a3 %in% c("IND", "AFG", "PAK", "NPL", "BGD", "LKA"))) +
  tm_borders() +
  
# Plot India
  tm_shape(india) +
  tm_polygons("name",legend.show = FALSE) +
  
# Plot Neighbours
  tm_shape(india_neighbours) +
  tm_polygons("name", legend.show = FALSE) +
  
# Plot the cities in India alone
  tm_shape(metro %>% dplyr::filter(iso_a3 == "IND")) +
  tm_dots(size = "pop2020",legend.size.show = FALSE) +
  tm_layout(legend.show = FALSE) +
  tm_credits("Geographical Boundaries are not accurate",
             size = 0.5,
             position = "right") +
  tm_compass(position = c("right", "top")) +
  tm_scale_bar(position = "left") +
  tmap_style("watercolor") 
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## tmap style set to "watercolor"
## other available styles are: "white", "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic"
## Credits not supported in view mode.
## Compass not supported in view mode.
## Warning: Number of levels of the variable "name" is 35, which is
## larger than max.categories (which is 30), so levels are combined. Set
## tmap_options(max.categories = 35) in the layer function to show all levels.
## Warning: Number of levels of the variable "name" is 112, which is
## larger than max.categories (which is 30), so levels are combined. Set
## tmap_options(max.categories = 112) in the layer function to show all levels.
#Try other map styles
#cobalt #gray #white #col_blind #beaver #classic #watercolor #albatross #bw

7.3 Map 2

tm_shape(india_neighbours) + 
  tm_polygons("name") + 
  
  tm_shape( metro %>% dplyr::filter(iso_a3 %in% c("IND","PAK", "LKA", "BGD","NPL"))) +
  tm_dots(size = "pop2020") + 
  tm_layout(legend.show = FALSE) + # no effect
  tmap_options(max.categories = 10) + 
  tm_credits("Geographical Boundaries are not accurate",size = 0.5,position = "center")
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## Credits not supported in view mode.
## Warning: Number of levels of the variable "name" is 112, which is
## larger than max.categories (which is 10), so levels are combined. Set
## tmap_options(max.categories = 112) in the layer function to show all levels.
## Legend for symbol sizes not available in view mode.
tmap_mode("view")
## tmap mode set to interactive viewing
tm_basemap("Stamen.Watercolor") +
  tm_shape(metro, bbox = "India") + 
  tm_dots(col = "red", 
          # user-chosen group name for layers
          group = "Metropolitan Areas") +
  tm_shape(World) + 
  tm_borders() + 
  tm_tiles(server = "Stamen.TonerLabels", group = "Labels") + # ADDS LABELS!!!
  tm_graticules()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()
## old-style crs object detected; please recreate object with a recent sf::st_crs()

7.4 Your Turn 2

Can you try to download a map area of your home town and plot it as we have above?

7.5 Adding my favourite “area” to the map

We can create areas of interest around the map. For a start: we are simply going to zoom in to an area, define a small rectangle, and say that is our area of interest.

This area then needs to go Through the Looking Glass and become part of the projection of dat_B!!

We can then try more complex queries and plots based on your favourite restaurants etc.

my_area <- bbox %>% 
  
  # zooming in within our bounding box area
  prettymapr::zoombbox(factor = 8, offset = c(0,0)) 
my_area
##        min      max
## x 77.59063 77.59937
## y 12.94313 12.94688
bbox
##     min   max
## x 77.56 77.63
## y 12.93 12.96

OK, my area is small and contained inside my bbox. So zoombbox works.

Now to convert my_area into a spatial dataframe using sf and add it to the blr_map plot:

# Make a matrix
my_area_in_blr <- matrix(
  c(
  my_area["x", "min"],
  my_area["x", "max"],
  my_area["x", "max"],
  my_area["x", "min"],
  my_area["x", "min"],
  my_area["y", "min"],
  my_area["y", "min"],
  my_area["y", "max"],
  my_area["y", "max"],
  my_area["y", "min"]),
  ncol = 2) 
my_area_in_blr
##          [,1]     [,2]
## [1,] 77.59063 12.94313
## [2,] 77.59937 12.94313
## [3,] 77.59937 12.94688
## [4,] 77.59063 12.94688
## [5,] 77.59063 12.94313

Note the A-B-C-D-A structure of specifying an enclosed area. Last vertex is the same as start vertex.

# Convert to list since POLYGON needs a list
my_area_in_blr <- 
  
  my_area_in_blr %>% 
  list() %>% 

# Convert to POLYGON
  st_polygon() %>% 
  
# Convert POLYGON to an `sfc` column
# Through the Looking Glass with dat_B
  st_sfc(., crs = st_crs(dat_B)) %>% 
  
  # Convert sfc to an sf spatial dataframe. Phew!!
  st_as_sf(.) 
  


my_area_in_blr
## Simple feature collection with 1 feature and 0 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 77.59062 ymin: 12.94312 xmax: 77.59937 ymax: 12.94688
## Geodetic CRS:  WGS 84
##                                x
## 1 POLYGON ((77.59063 12.94313...
blr_map <- 
  blr_map + geom_sf(data = my_area_in_blr, colour = "red")
blr_map

We could have created an arbitrary area on our map in this way, starting with a matrix and making a spatial data frame, and over-plotting it as a layer on the base map.

We could also add multiple areas of interest using …yes MULTIPOLYGONs !!

7.6 Your Turn 3

Try adding more than one “areas of interest” to your map.

7.7 Adding my favourite Restaurants to the map

Is it time to order on Swiggy…

Let us adding interesting places to our map: say based on your favourite restaurants etc. We need restaurant data: lat/long + name + maybe type of restaurant. This can be manually created ( like all of OSMdata ) or if it is already there we can download using key-value pairs in our OSM data query.

dat_R <- extract_osm_objects(bbox = bbox, 
                             key = "amenity", 
                             value = "restaurant", 
                             return_type = "point") #<<
## Issuing query to Overpass API ...
## Error in curl::curl_fetch_memory(url, handle = handle): Empty reply from server
## Request failed [ERROR]. Retrying in 1 seconds...
## Error in curl::curl_fetch_memory(url, handle = handle): Send failure: Connection was aborted
## Request failed [ERROR]. Retrying in 2.1 seconds...
## Error in curl::curl_fetch_memory(url, handle = handle): schannel: failed to receive handshake, SSL/TLS connection failed
## Request failed [ERROR]. Retrying in 7.2 seconds...
## Rate limit: 0
## Query complete!
## converting OSM data to sf format

Note the return_type parameter: we want the location and not the building in which the restaurant is!!

# How many restaurants have we got?
dat_R %>% nrow()
## [1] 300
names(dat_R)
##  [1] "osm_id"             "name"               "addr.city"         
##  [4] "addr.country"       "addr.floor"         "addr.hamlet"       
##  [7] "addr.housename"     "addr.housenumber"   "addr.place"        
## [10] "addr.postcode"      "addr.street"        "alt_name"          
## [13] "amenity"            "capacity"           "contact.phone"     
## [16] "cuisine"            "delivery"           "description"       
## [19] "designation"        "diet.vegan"         "diet.vegetarian"   
## [22] "email"              "food"               "internet_access"   
## [25] "level"              "name.en"            "name.kn"           
## [28] "note"               "opening_hours"      "operator"          
## [31] "outdoor_seating"    "phone"              "smoking"           
## [34] "source"             "speciality"         "takeaway"          
## [37] "toilets.wheelchair" "website"            "wheelchair"        
## [40] "wikidata"           "wikipedia"          "geometry"
# Let's look at the `cuisine` column! 
# ( I want pizza...)
dat_R$cuisine
##   [1] NA                             NA                            
##   [3] NA                             NA                            
##   [5] NA                             NA                            
##   [7] NA                             "indian"                      
##   [9] NA                             NA                            
##  [11] "indian"                       NA                            
##  [13] "chinese"                      NA                            
##  [15] NA                             NA                            
##  [17] NA                             NA                            
##  [19] "regional"                     NA                            
##  [21] "Mughlai"                      NA                            
##  [23] "chinese"                      "north indian"                
##  [25] NA                             "chinese"                     
##  [27] "chinese"                      NA                            
##  [29] "indian"                       NA                            
##  [31] "tandoor"                      NA                            
##  [33] NA                             NA                            
##  [35] "regional"                     "Naga"                        
##  [37] "chinese"                      NA                            
##  [39] NA                             NA                            
##  [41] "chinese"                      NA                            
##  [43] NA                             NA                            
##  [45] NA                             "indian"                      
##  [47] "spanish"                      NA                            
##  [49] "indian"                       "chinese"                     
##  [51] NA                             NA                            
##  [53] NA                             "indian"                      
##  [55] NA                             "indian"                      
##  [57] "indian"                       "ice_cream"                   
##  [59] "chinese"                      "indian"                      
##  [61] NA                             "ice_cream"                   
##  [63] "indian"                       NA                            
##  [65] "indian"                       "indian"                      
##  [67] "international"                NA                            
##  [69] "international"                NA                            
##  [71] "ice_cream"                    "seafood"                     
##  [73] NA                             NA                            
##  [75] "indian"                       "international"               
##  [77] "chinese"                      "indian"                      
##  [79] "indian"                       "chinese"                     
##  [81] "indian"                       "international"               
##  [83] "ice_cream"                    "ice_cream"                   
##  [85] NA                             "italian"                     
##  [87] NA                             NA                            
##  [89] "indian"                       "chinese"                     
##  [91] "ice_cream"                    "international"               
##  [93] "indian"                       NA                            
##  [95] NA                             "coffee_shop"                 
##  [97] "international"                NA                            
##  [99] NA                             NA                            
## [101] "indian"                       "international"               
## [103] "international"                "international"               
## [105] "international"                "indian"                      
## [107] NA                             NA                            
## [109] NA                             NA                            
## [111] NA                             NA                            
## [113] "indian"                       "international"               
## [115] NA                             NA                            
## [117] NA                             NA                            
## [119] "chinese"                      NA                            
## [121] "indian"                       NA                            
## [123] NA                             "indian"                      
## [125] "chinese"                      "indian"                      
## [127] "indian"                       "indian"                      
## [129] NA                             "international"               
## [131] "indian"                       NA                            
## [133] "italian"                      NA                            
## [135] "indian"                       "indian"                      
## [137] "regional"                     "indian"                      
## [139] "international"                NA                            
## [141] "regional"                     NA                            
## [143] NA                             NA                            
## [145] "chinese"                      "pizza"                       
## [147] NA                             NA                            
## [149] NA                             NA                            
## [151] NA                             NA                            
## [153] NA                             NA                            
## [155] NA                             NA                            
## [157] NA                             NA                            
## [159] NA                             NA                            
## [161] NA                             NA                            
## [163] "pizza"                        "Multi-cuisne"                
## [165] "indian"                       "indian"                      
## [167] "indian"                       NA                            
## [169] "andhra"                       NA                            
## [171] NA                             NA                            
## [173] NA                             NA                            
## [175] "regional"                     NA                            
## [177] "regional"                     "regional"                    
## [179] "regional"                     "regional"                    
## [181] "regional"                     "regional"                    
## [183] "regional"                     "regional"                    
## [185] "regional"                     "regional"                    
## [187] "regional"                     "regional"                    
## [189] "regional"                     "regional"                    
## [191] "regional"                     "regional"                    
## [193] "regional"                     "regional"                    
## [195] "italian"                      "regional"                    
## [197] "italian"                      "regional"                    
## [199] "regional"                     "regional"                    
## [201] "regional"                     "regional"                    
## [203] "regional"                     "regional"                    
## [205] "regional"                     "regional"                    
## [207] "regional"                     "regional"                    
## [209] "regional"                     NA                            
## [211] "regional"                     "regional"                    
## [213] "regional"                     "regional"                    
## [215] "regional"                     "regional"                    
## [217] "regional"                     "regional"                    
## [219] "regional"                     "regional"                    
## [221] "regional"                     "regional"                    
## [223] "regional"                     "regional"                    
## [225] "regional"                     "regional"                    
## [227] "regional"                     "regional"                    
## [229] "regional"                     "regional"                    
## [231] "regional"                     "regional"                    
## [233] "regional"                     "kebab;grill"                 
## [235] "indian"                       NA                            
## [237] "indian,_japanese"             "italian"                     
## [239] "italian_pizza;italian"        NA                            
## [241] NA                             "regional"                    
## [243] NA                             NA                            
## [245] NA                             NA                            
## [247] NA                             NA                            
## [249] NA                             NA                            
## [251] NA                             NA                            
## [253] NA                             NA                            
## [255] NA                             NA                            
## [257] NA                             NA                            
## [259] NA                             NA                            
## [261] NA                             NA                            
## [263] NA                             "indian"                      
## [265] NA                             NA                            
## [267] NA                             NA                            
## [269] NA                             NA                            
## [271] NA                             NA                            
## [273] NA                             NA                            
## [275] NA                             NA                            
## [277] NA                             NA                            
## [279] NA                             NA                            
## [281] NA                             NA                            
## [283] NA                             NA                            
## [285] NA                             NA                            
## [287] "asian"                        NA                            
## [289] NA                             NA                            
## [291] "indian;north_indian;regional" NA                            
## [293] "chinese;chicken;asian;indian" NA                            
## [295] "indian"                       NA                            
## [297] "indian"                       NA                            
## [299] NA                             NA

So let us plot the restaurants as POINTs using the dat-R data we have downloaded. The cuisine attribute looks interesting; let us colour the POINT based on the cuisine offered at that restaurant.

The cuisine attribute:
Note: The cuisine variable has more than one entry for a given restaurant. We use tidyr::separate() to make multiple columns out of the cuisine column and retain the first one only. Since the entries are badly entered using both “;” and “,” we need to do this twice ;-()
dat_R <- dat_R %>% 
  drop_na(cuisine) %>% # Knock off nondescript restaurants
  
  # Some have more than on classification ;-()
  # Separated by semicolon or comma, so....
  separate(col = cuisine, into = c("cuisine", NA, NA), sep = ";") %>% 
  separate(col = cuisine, into = c("cuisine", NA, NA), sep = ",")
## Warning: Expected 3 pieces. Additional pieces discarded in 1 rows [150].
## Warning: Expected 3 pieces. Missing pieces filled with `NA` in 150 rows [1, 2,
## 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].
## Warning: Expected 3 pieces. Missing pieces filled with `NA` in 152 rows [1, 2,
## 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...].
# Finally good food?
dat_R$cuisine
##   [1] "indian"        "indian"        "chinese"       "regional"     
##   [5] "Mughlai"       "chinese"       "north indian"  "chinese"      
##   [9] "chinese"       "indian"        "tandoor"       "regional"     
##  [13] "Naga"          "chinese"       "chinese"       "indian"       
##  [17] "spanish"       "indian"        "chinese"       "indian"       
##  [21] "indian"        "indian"        "ice_cream"     "chinese"      
##  [25] "indian"        "ice_cream"     "indian"        "indian"       
##  [29] "indian"        "international" "international" "ice_cream"    
##  [33] "seafood"       "indian"        "international" "chinese"      
##  [37] "indian"        "indian"        "chinese"       "indian"       
##  [41] "international" "ice_cream"     "ice_cream"     "italian"      
##  [45] "indian"        "chinese"       "ice_cream"     "international"
##  [49] "indian"        "coffee_shop"   "international" "indian"       
##  [53] "international" "international" "international" "international"
##  [57] "indian"        "indian"        "international" "chinese"      
##  [61] "indian"        "indian"        "chinese"       "indian"       
##  [65] "indian"        "indian"        "international" "indian"       
##  [69] "italian"       "indian"        "indian"        "regional"     
##  [73] "indian"        "international" "regional"      "chinese"      
##  [77] "pizza"         "pizza"         "Multi-cuisne"  "indian"       
##  [81] "indian"        "indian"        "andhra"        "regional"     
##  [85] "regional"      "regional"      "regional"      "regional"     
##  [89] "regional"      "regional"      "regional"      "regional"     
##  [93] "regional"      "regional"      "regional"      "regional"     
##  [97] "regional"      "regional"      "regional"      "regional"     
## [101] "regional"      "regional"      "italian"       "regional"     
## [105] "italian"       "regional"      "regional"      "regional"     
## [109] "regional"      "regional"      "regional"      "regional"     
## [113] "regional"      "regional"      "regional"      "regional"     
## [117] "regional"      "regional"      "regional"      "regional"     
## [121] "regional"      "regional"      "regional"      "regional"     
## [125] "regional"      "regional"      "regional"      "regional"     
## [129] "regional"      "regional"      "regional"      "regional"     
## [133] "regional"      "regional"      "regional"      "regional"     
## [137] "regional"      "regional"      "regional"      "regional"     
## [141] "kebab"         "indian"        "indian"        "italian"      
## [145] "italian_pizza" "regional"      "indian"        "asian"        
## [149] "indian"        "chinese"       "indian"        "indian"

Now let’s plot the Restaurants as POINTs:

# http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf
# 
ggplot() + 
  geom_sf(data = dat_B, colour = "burlywood1") + 
  geom_sf(data = dat_H, colour = "gray80") +
  geom_sf(data = dat_R %>% drop_na(cuisine), aes(fill = cuisine), colour = "black", shape = 21) + 
  theme(legend.position = "right") +
  labs(title = "Restaurants in South Central Bangalore",
       caption = "Based on osmdata")

We could have done a (much!) better job, by combining cuisines into simpler and fewer categories, but that is for another day!!

By now we know that we can use geom_sf() multiple number of times with different datasets to create layered maps in R.

8 Scope and Packages for Exploration!!

8.0.1 sfnetworks

8.0.2 mapsf

8.0.3 ggspatial

9 Resources

  1. Emine Fidan, Guide to Creating Interactive Maps in R

  2. Nikita Voevodin,R, Not the Best Practices

10 Assignments

  1. What if we have marked our favourite locations on our smartphones, using GPS? Umm…OK have to make our sf:Spatial Data Frame using these coordinates. We will need to do this in the same way:
  • Create a matrix
  • Make POINTs
  • Make an sfc
  • Convert to sf
  • Project in the same way.
  1. Draw a map of your home-town with your favourite restaurants shown. Pop-ups for each restaurant will win bonus points.

11 Inspiration

  1. Burkhart, Christian. n.d. “Streetmaps.” StreetMaps

  1. Making Vector Maps, Computing for the Social Sciences, Univ. of Chicago
LS0tDQp0aXRsZTogIkxhYi0wNjogVGhlIEdyYW1tYXIgb2YgTWFwcyINCnN1YnRpdGxlOiAiV2hlcmUgaXMgdGhlIFNlY3JldCBHYXJkZW4/Ig0KYXV0aG9yOiAiQXJ2aW5kIFZlbmthdGFkcmkiDQpkYXRlOiAyMi9BcHJpbC8yMDIxDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KICAgIHRvY19kZXB0aDogMg0KICAgIG51bWJlcl9zZWN0aW9uczogVFJVRQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUNCmFic3RyYWN0OiBQYXJ0IG9mIHRoZSBgUiBmb3IgQXJ0aXN0cyBhbmQgRGVzaWduZXJzYCB3b3Jrc2hvcCBjb3Vyc2UgYXQgdGhlIFNjaG9vbCBvZiBGb3VuZGF0aW9uIFN0dWRpZXMsIFNyaXNodGkgTWFuaXBhbCBJbnN0aXR1dGUgb2YgQXJ0LCBEZXNpZ24sIGFuZCBUZWNobm9sb2d5LCBCYW5nYWxvcmUuDQotLS0NCg0KDQojIEludHJvZHVjdGlvbg0KDQpUaGlzIFJNYXJrZG93biBkb2N1bWVudCBpcyBwYXJ0IG9mIHRoZSBHZW5lcmljIFNraWxscyBDb21wb25lbnQgIChHU0spIG9mIHRoZSBDb3Vyc2Ugb2YgdGhlICBGb3VuZGF0aW9uIFN0dWRpZXMgUHJvZ3JhbW1lIGF0IFNyaXNodGkgTWFuaXBhbCBJbnN0aXR1dGUgb2YgQXJ0LCBEZXNpZ24sIGFuZCBUZWNobm9sb2d5LCBCYW5nYWxvcmUgSW5kaWEuIFRoZSBtYXRlcmlhbCBpcyBiYXNlZCBvbiAqQSBMYXllcmVkIEdyYW1tYXIgb2YgR3JhcGhpY3MqIGJ5IEhhZGxleSBXaWNraGFtLiBUaGUgY291cnNlIGlzIG1lYW50IGZvciBGaXJzdCBZZWFyIHN0dWRlbnRzIHB1cnN1aW5nIGEgRGVncmVlIGluIEFydCBhbmQgRGVzaWduLiANCg0KVGhlIGludGVudCBvZiB0aGlzIEdTSyBwYXJ0IGlzIHRvIGJ1aWxkIFNraWxsIGluIGNvZGluZyBpbiBSLCBhbmQgYWxzbyBhcHByZWNpYXRlIFIgYXMgYSB3YXkgdG8gbWV0YXBob3JpY2FsbHkgdmlzdWFsaXplIGluZm9ybWF0aW9uIG9mIHZhcmlvdXMga2luZHMsIHVzaW5nIHByZWRvbWluYW50bHkgZ2VvbWV0cmljIGZpZ3VyZXMgYW5kIHN0cnVjdHVyZXMuDQoNCkFsbCBSTWFya2Rvd24gZmlsZXMgY29tYmluZSBjb2RlLCB0ZXh0LCB3ZWItaW1hZ2VzLCBhbmQgZmlndXJlcyBkZXZlbG9wZWQgdXNpbmcgY29kZS4gRXZlcnl0aGluZyBpcyB0ZXh0OyBjb2RlIGNodW5rcyBhcmUgZW5jbG9zZWQgaW4gKipmZW5jZXMqKiAoYGBgKQ0KDQoNCiMgR29hbHMNCg0KQXQgdGhlIGVuZCBvZiB0aGlzIExhYiBzZXNzaW9uLCB3ZSBzaG91bGQ6DQotIGtub3cgdGhlIHR5cGVzIGFuZCBzdHJ1Y3R1cmVzIG9mIGBzcGF0aWFsIGRhdGFgIGFuZCBiZSBhYmxlIHRvIHdvcmsgd2l0aCB0aGVtDQotIHVuZGVyc3RhbmQgdGhlIGJhc2ljcyBvZiBtb2Rlcm4gc3BhdGlhbCBwYWNrYWdlcyBpbiBSDQotIGJlIGFibGUgdG8gc3BlY2lmeSBhbmQgZG93bmxvYWQgc3BhdGlhbCBkYXRhIGZyb20gdGhlIHdlYiwgdXNpbmcgUiBmcm9tIHNvdXJjZXMgc3VjaCBhcyBgbmF0dXJhbGVhcnRoYCBhbmQgYE9wZW4gU3RyZWVwIE1hcGANCi0gcGxvdCAqc3RhdGljKiBhbmQgKmludGVyYWN0aXZlKiBtYXBzIHVzaW5nIGBnZ3Bsb3RgLCBgdG1hcGAgYW5kIGBsZWFmbGV0YCBwYWNrYWdlcw0KLSBhZGQgc3ltYm9scyBhbmQgbWFya2VycyBmb3IgcGxhY2VzIGFuZCByZWdpb25zIG9mIG91ciBvd24gaW50ZXJlc3QgaW4gdGhlc2UgbWFwcy4NCi0gc2VlIGRpcmVjdGlvbnMgZm9yIGZ1cnRoZXIgd29yayAoZS5nLiBtYXBzICsgbmV0d29ya3MgdG9nZXRoZXIpDQoNCg0KDQojIFBlZGFnb2dpY2FsIE5vdGUNCg0KVGhlIG1ldGhvZCBmb2xsb3dlZCB3aWxsIGJlIGJhc2VkIG9uDQpbUFJJTU1dKGh0dHBzOi8vYmxvZ3Mua2NsLmFjLnVrL2NzZXIvMjAxNy8wOS8wMS9wcmltbS1hLXN0cnVjdHVyZWQtYXBwcm9hY2gtdG8tdGVhY2hpbmctcHJvZ3JhbW1pbmcvKToNCg0KLSAgICoqUFJFRElDVCoqIEluc3BlY3QgdGhlIGNvZGUgYW5kIGd1ZXNzIGF0IHdoYXQgdGhlIGNvZGUgbWlnaHQgZG8sDQogICAgKip3cml0ZSBwcmVkaWN0aW9ucyoqDQotICAgKipSVU4qKiB0aGUgY29kZSBwcm92aWRlZCBhbmQgY2hlY2sgd2hhdCBoYXBwZW5zDQotICAgKipJTkZFUioqIHdoYXQgdGhlIGBwYXJhbWV0ZXJzYCBvZiB0aGUgY29kZSBkbyBhbmQgKip3cml0ZSBjb21tZW50cyB0byBleHBsYWluKiouIFdoYXQgYmVsbHMgYW5kIHdoaXN0bGVzIGNhbiB5b3Ugc2VlPw0KLSAgICoqTU9ESUZZKiogdGhlIGBwYXJhbWV0ZXJzYCBjb2RlIHByb3ZpZGVkIHRvIHVuZGVyc3RhbmQgdGhlDQogICAgYG9wdGlvbnNgIGF2YWlsYWJsZS4gKipXcml0ZSBjb21tZW50cyoqIHRvIHNob3cgd2hhdCB5b3UgaGF2ZSBhaW1lZCBmb3IgYW5kIGFjaGlldmVkLg0KLSAgICoqTUFLRSoqIDogdGFrZSBhbiBpZGVhL2NvbmNlcHQgb2YgeW91ciBvd24sIGFuZCBncmFwaCBpdC4NCg0KDQojIyBTZXQgVXANCg0KVGhlIGBzZXR1cGAgY29kZSAqKmNodW5rKiogYmVsb3cgYnJpbmdzIGludG8gb3VyIGNvZGluZyBzZXNzaW9uICoqUiBwYWNrYWdlcyoqIHRoYXQgcHJvdmlkZSBzcGVjaWZpYyBjb21wdXRhdGlvbmFsIGFiaWxpdGllcyBhbmQgYWxzbyAqKmRhdGFzZXRzKiogd2hpY2ggd2UgY2FuIHVzZS4gDQoNClRvIHJlaXRlcmF0ZTogUGFja2FnZXMgYW5kIGRhdGFzZXRzIGFyZSAqKm5vdCoqIHRoZSBzYW1lIHRoaW5nICEhIFBhY2thZ2VzIGFyZSAoc21hbGwpIGNvbGxlY3Rpb25zIG9mIHByb2dyYW1zLiBEYXRhc2V0cyBhcmUganVzdC4uLi5pbmZvcm1hdGlvbi4NCg0KIyBQYWNrYWdlIHJlbGF0ZWQgSW5zdHJ1Y3Rpb25zDQoNCiAtIEluc3RhbGwgYWxsIHBhY2thZ2VzIHRoYXQgYXJlIGZsYWdnZWQgYnkgUlN0dWRpbw0KIC0gUnVuIHRoaXMgaW4geW91ciBjb25zb2xlIGZpcnN0Og0KDQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInJvcGVuc2NpL3JuYXR1cmFsZWFydGhoaXJlcyIpDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQojIEdldHRpbmcgTWFwIERhdGEgaW50byBSDQpsaWJyYXJ5KG9zbWRhdGEpICMgSW1wb3J0IE9wZW4gU3RyZWV0IERhdGENCmxpYnJhcnkocm5hdHVyYWxlYXJ0aCkNCmxpYnJhcnkocm5hdHVyYWxlYXJ0aGRhdGEpDQpsaWJyYXJ5KHJuYXR1cmFsZWFydGhoaXJlcykNCiMgUnVuIHRoaXMgaW4geW91ciBjb25zb2xlIGZpcnN0DQojZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyb3BlbnNjaS9ybmF0dXJhbGVhcnRoaGlyZXMiKQ0KIyANCmxpYnJhcnkocHJldHR5bWFwcikgIyB0byBzZWFyY2ggZm9yIG1hcCBkYXRhIGJhc2VkIG9uIGxvY2F0aW9uDQoNCiMgUGxvdHRpbmcgTWFwcw0KbGlicmFyeSh0aWR5dmVyc2UpICMgTWFwcyB1c2luZyBnZ3Bsb3QgKyBnZW9tX3NmDQpsaWJyYXJ5KG9zbXBsb3RyKSAjICJCZXNwb2tlIiBNYXBzIHVzaW5nIE9TTSBkYXRhDQpsaWJyYXJ5KHRtYXApICMgVGhlbWF0aWMgTWFwcywgc3RhdGljIGFuZCBpbnRlcmFjdGl2ZQ0KDQojIEZvciBTcGF0aWFsIERhdGEgRnJhbWUgUHJvY2Vzc2luZw0KbGlicmFyeShzZikNCg0KYGBgDQoNCg0KIyBJbnRyb2R1Y3Rpb24gdG8gTWFwcyBpbiBSDQoNCldlIHdpbGwgdGFrZSBzbWFsbCBzdGVwcyBpbiBtYWtpbmcgbWFwcyB1c2luZyBqdXN0IHR3byBvZiB0aGUgc2V2ZXJhbCBtYXAgbWFraW5nIHBhY2thZ2VzIGluIFIuDQoNClRoZSBzdGVwcyB3ZSB3aWxsIHVzZSBhcmU6DQoNCjEuIFNlYXJjaCBmb3IgYW4gYXJlYSBvZiBpbnRlcmVzdCAoIEUuZy4gdXNpbmcgYHByZXR0eW1hcHJgIG9yIHNpbWlsYXIuLikNCjIuIExlYXJuIGhvdyB0byBhY2Nlc3Mgc3BhdGlhbC9tYXAgZGF0YSB1c2luZyBgb3NtZGF0YWANCjMuIFBsb3QgYW5kIGRyZXNzIHVwIG91ciBtYXAgdXNpbmcgYG9zbXBsb3RgLCBgdG1hcGAgYW5kIGFsc28gd2l0aCBgbGVhZmxldGAuDQo0LiBDcmVhdGUgaW50ZXJhY3RpdmUgbWFwcyB3aXRoIGBsZWFmbGV0YCB1c2luZyBhIHZhcmlldHkgb2YgbWFwIGRhdGEgcHJvdmlkZXJzLiBOb3RlOiBgdG1hcGAgY2FuIGFsc28gZG8gaW50ZXJhY3RpdmUgbWFwcyB3aGljaCB3ZSB3aWxsIGV4cGxvcmUgYWxzby4gDQoNCkJhcy4gT253YXJkcyBhbmQgTWFwLXdhcmRzISENCg0KQWxsIGphcmdvbiB3b3JkcyB3aWxsIGJlIGNhcGl0YWxpemVkIGFuZCBpbiAqKmJvbGQqKiBmb250LiANCg0KIyBHb2QgbWFkZSBtZSBhIEJlbmdhbHVSLWthUi4uLkkgdGhpbmsNCg0KTGV0J3MgZ2V0IEJMUiBkYXRhIGludG8gUiBhbmQgc2VlIGlmIHdlIGNhbiBwbG90IGFuIGFyZWEgb2YgaW50ZXJlc3QuIFRoZW4gd2UgY2FuIG9yZGVyIG9uIFN3aWdneSBhbmQuLi5uZXZlciBtaW5kLiANCg0KDQoxLiBXaGVyZSBpcyBteSBob21lPyBTcGVjaWZ5IGEgIioqQk9VTkRJTkcgQk9YKioiIGZpcnN0LCB1c2luZyBhIHJvdWdoIGxvbmdpdHVkZSBsYXRpdHVkZSBpbmZvIGRpcmVjdGx5LCBvciB1c2luZyBhIHBsYWNlIG5hbWUgdG8gc2VhcmNoIGZvciB0aGUgbG9uZy9sYXQgaW5mbzoNCg0KYGBge3IgSV9hbV9nb2luZ19ob21lfQ0KIyBCTFIgQm91bmRpbmcgQm94DQojIGdldF9iYm94IG5lZWRzIGxhdCBhbmQgbG9uIHJhbmdlcw0KYmJveCA8LSBvc21wbG90cjo6Z2V0X2Jib3goYyg3Ny41NiwxMi45Myw3Ny42MywxMi45NikpDQoNCmJib3hfbCA8LSBvc21kYXRhOjpnZXRiYigiQmFuZ2Fsb3JlLCBJbmRpYSIpICMgTEFSR0UNCmJib3hfcCA8LSBwcmV0dHltYXByOjpzZWFyY2hiYm94KCJCYW5nYWxvcmUiKSAjIEFMU08gTEFSR0UNCmJib3gNCmJib3hfbA0KYmJveF9wICMgaWRlbnRpY2FsIHdpdGggYmJveF9sDQpgYGANCldlIHdpbGwgdXNlIHRoZSBzbWFsbGVyIGBiYm94YCBmcm9tIHRoZSBhYm92ZSwgdG8gZW5zdXJlIHdlIGhhdmUgc21hbGxlciBkYXRhIGRvd25sb2FkcyEgDQoNCldpdGhpbiBvdXIgYmJveCBmb3IgQkxSLCB3ZSB3YW50IHRvIGRvd25sb2FkIGRpdmVyc2Uga2luZHMgb2YgKipGRUFUVVJFKiogZGF0YS4gUmVtZW1iZXIgdGhhdCBhICoqRkVBVFVSRSoqIFRoaXMgaXMgZG9uZSB1c2luZyB0aGUgYG9zbXBsb3RyOjpleHRyYWN0X29zbV9vYmplY3RzKClgIGNvbW1hbmQuIFRoZSBtYWluIHBhcmFtZXRlcnMgZm9yIHRoaXMgY29tbWFuZCBhcmU6DQoNCi0gYmJveCAgDQotICoqS0VZIC8gVkFMVUUqKiBwYWlycyAoKioiVEFHUyIqKikgdG8gc3BlY2lmeSB0aGUga2luZCBvZiBmZWF0dXJlIHlvdSBuZWVkICANCg0KU2VlIFtPU00gVGFnc10oaHR0cHM6Ly90YWdpbmZvLm9wZW5zdHJlZXRtYXAub3JnLykgZm9yIGEgbmljZSB2aXN1YWwgZGVzY3JpcHRpb24gb2YgcG9wdWxhciB0YWdzIHRoYXQgd2UgY2FuIHVzZS4gVXNlZnVsIGtleXMgaW5jbHVkZToNCi0gYnVpbGRpbmcgOiB5ZXMgKGFsbCksIGhvdXNlIHJlc2lkZW50aWFsLCBhcGFydG1lbnRzDQotIGhpZ2h3YXk6IHJlc2lkZW50aWFsLCBzZXJ2aWNlLCB0cmFjaywgdW5jbGFzc2lmaWVkLCBmb290d2F5LCBwYXRoDQotIGFtZW5pdHk6IHBhcmtpbmcsIHBhcmtpbmdfc3BhY2UsIGJlbmNoOyBwbGFjZV9vZl93b3JzaGlwOyAgcmVzdGF1cmFudCwgY2FmZSwgZmFzdF9mb29kOyBzY2hvb2wsIHdhc3RlX2Jhc2tldCwgZnVlbCwgYmFuaywgdG9pbGV0cy4uLg0KLSBzaG9wOiBjb252ZW5pZW5jZSwgc3VwZXJtYXJrZXQsIGNsb3RoZXMsIGhhaXJkcmVzc2VyLCBjYXItcmVwYWlyLi4uDQotIG5hbWU6IGFjdHVhbCBuYW1lIG9mIHRoZSBwbGFjZSBlLmcuIE1haW5fU3RyZWV0LCBNY0RvbmFsZCdzLCBQaXp6YSBIdXQsIFN1YndheQ0KLSB3YXRlcndheQ0KLSBuYXR1cmFsLCANCi0gYm91bmRhcnkNCi0gaGlnaHdheSouDQoNCkZvciBleGFtcGxlIHNlZTogW3RhZyA6IGhpZ2h3YXldKGh0dHBzOi8vdGFnaW5mby5vcGVuc3RyZWV0bWFwLm9yZy9rZXlzL2hpZ2h3YXkjdmFsdWVzKQ0KDQpgYGB7ciBnZXRfb3NtX21hcF9kYXRhLCBjYWNoZSA9IFRSVUUsIG1lc3NhZ2U9RkFMU0V9DQojIEdldCBNYXAgZGF0YQ0KDQpkYXRfQiA8LSBleHRyYWN0X29zbV9vYmplY3RzIChrZXkgPSAiYnVpbGRpbmciLCBiYm94ID0gYmJveCkgDQpkYXRfSCA8LSBleHRyYWN0X29zbV9vYmplY3RzIChrZXkgPSAnaGlnaHdheScsIGJib3ggPSBiYm94KQ0KZGF0X1AgPC0gZXh0cmFjdF9vc21fb2JqZWN0cyAoa2V5ID0gJ3BhcmsnLCBiYm94ID0gYmJveCkNCmRhdF9HIDwtIGV4dHJhY3Rfb3NtX29iamVjdHMgKGtleSA9ICdsYW5kdXNlJywgdmFsdWUgPSAnZ3Jhc3MnLCBiYm94ID0gYmJveCkNCmRhdF9UIDwtIGV4dHJhY3Rfb3NtX29iamVjdHMgKGtleSA9ICduYXR1cmFsJywgdmFsdWUgPSAndHJlZScsIGJib3ggPSBiYm94KQ0KDQoNCmBgYA0KIyMgTGV0J3MgbG9vayBhdCB0aGUgZGF0YQ0KDQpgYGB7cn0NCiMgSG93IG1hbnkgYnVpbGRpbmdzPw0KbnJvdyhkYXRfQikNCmRhdF9CJGdlb21ldHJ5DQpjbGFzcyhkYXRfQiRnZW9tZXRyeSkNCmBgYA0KDQpTbyBgZGF0X0JgIGhhcyBgciBucm93KGRhdF9CKWAgYnVpbGRpbmdzIGFuZCB0aGVpciBnZW9tZXRyeSBpcyBuYXR1cmFsbHkgYSBQT0xZR09OIHR5cGUgb2YgZ2VvbWV0cnkgY29sdW1uLiANCg0KDQojIyBZb3VyIFR1cm4gMQ0KRG8gdGhpcyBjaGVjayBmb3IgYWxsIHRoZSBvdGhlciBzcGF0aWFsIGRhdGEsIGluIHRoZSBjb2RlIGNodW5rIGJlbG93LiANCg0KV2hhdCBraW5kIG9mIGBnZW9tZXRyeWAgY29sdW1uIGRvZXMgZWFjaCBkYXRhc2V0IGhhdmU/DQoNCg0KYGBge3IgWU9VUl9UVVJOXzF9DQoNCg0KDQpgYGANCg0KDQoNCg0KIyMgV2hhdCBPdGhlciBLaW5kcyBvZiBEYXRhIGNvdWxkIHdlIGdldCBmcm9tIE9TTT8NCg0KYG9zbV9zdHJ1Y3R1cmVzYCByZXR1cm5zIGEgZGF0YS5mcmFtZSBvZiBPU00gc3RydWN0dXJlIHR5cGVzLCBhc3NvY2lhdGVkIGtleS12YWx1ZSBwYWlycywgdW5pcXVlIHN1ZmZpY2VzIHdoaWNoIG1heSBiZSBhcHBlbmRlZCB0byBkYXRhIHN0cnVjdHVyZXMgZm9yIHN0b3JhZ2UgcHVycG9zZXMsIGFuZCBzdWdnZXN0ZWQgY29sb3Vycy4NCg0KYGBge3J9DQpvc21fc3RydWN0dXJlcygpDQpgYGANCg0KDQoNCiMjIE15IGZpcnN0IE1hcCBpbiBSDQoNCldlIGNvdWxkIHF1aWNrbHkgcGxvdCB0aGlzIHVzaW5nIHRoZSBwYWNrYWdlIGBvc21wbG90cmAuIEhvd2V2ZXIsIGluIG15ICggaS5lLiBBcnZpbmQncyBvcGluaW9uICkgaXQgaXMgbm90IGFzIGZsZXhpYmxlIGFzIG90aGVyIHBhY2thZ2VzLiBNYXliZSBJIG5lZWQgdG8gc3R1ZHkgaXQgaW4gbW9yZSBkZXRhaWwuIA0KDQpTbyB3ZSB3aWxsIGNvbnRpbnVlIHdpdGggYGdncGxvdGAgYW5kIGBnZW9tX3NmKClgIDoNCg0KYGBge3J9DQoNCmJscl9tYXAgPC0gZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBkYXRfQiwgY29sb3VyID0gIm9yYW5nZSIpICsgICMgUE9MWUdPTlMNCiAgZ2VvbV9zZihkYXRhID0gZGF0X0gsIGNvbCA9ICJncmF5MjAiKSArICAgICAjIExJTkVTDQogIGdlb21fc2YoZGF0YSA9IGRhdF9HLCBjb2wgPSAiZGFya3NlYWdyZWVuMSIpICsgDQogIGdlb21fc2YoZGF0YSA9IGRhdF9QLCBjb2wgPSAiZGFya3NlYWdyZWVuIikgKw0KICBnZW9tX3NmKGRhdGEgPSBkYXRfVCwgY29sID0gImdyZWVuIikgICAgICAgICMgUE9JTlRTDQpibHJfbWFwDQoNCg0KYGBgDQoNCg0KTm90ZSBob3cgYGdlb21fc2ZgIGlzIGNhcGFibGUgb2YgaGFuZGxpbmcgKmFueSogZ2VvbWV0cnkgaW4gdGhlIGBzZmNgIGNvbHVtbiAhISANCg0KPiBgZ2VvbV9zZigpYCBpcyBhbiB1bnVzdWFsIGdlb20gYmVjYXVzZSBpdCB3aWxsIGRyYXcgZGlmZmVyZW50IGdlb21ldHJpYyBvYmplY3RzIGRlcGVuZGluZyBvbiB3aGF0IHNpbXBsZSBmZWF0dXJlcyBhcmUgcHJlc2VudCBpbiB0aGUgZGF0YTogeW91IGNhbiBnZXQgcG9pbnRzLCBsaW5lcywgb3IgcG9seWdvbnMuDQoNClNvIHRoZXJlLCB3ZSBoYXZlIG91ciBmaXJzdCBtYXAhDQoNCg0KIyBVc2luZyBgcm5hdHVyYWxlYXJ0aGAgYW5kIGB0bWFwYA0KDQpMZXQncyBwbG90IGEgZmlyc3QgbWFwIHVzaW5nIGRhdGFzZXRzIGJ1aWx0IGludG8gYHRtYXBgLiBUaGVuIHdlIGNhbiBkb3dubG9hZCBvdGhlciBkYXRhc2V0cyBmcm9tIGBybmF0dXJhbGVhcnRoYCBhbmQgcGxvdCB0aGVtIG5leHQuDQoNCmB0bWFwYCBoYXMgYSBmZXcgYnVpbHQtaW4gc3BhdGlhbCBkYXRhc2V0czogYFdvcmxkYCBhbmQgYG1ldHJvYCwgYHJpdmVyc2AsIGBsYW5kYCBhbmQgYSBmZXcgb3RoZXJzLiBDaGVjayBoZWxwIG9uIHRoZXNlLg0KDQpgYGB7ciBXb3JsZF9EYXRhX3RtYXB9DQpkYXRhKCJXb3JsZCIpDQpoZWFkKFdvcmxkLCBuID0gMykNCmBgYA0KDQpXZSBoYXZlIHNldmVyYWwgMTQgYXR0cmlidXRlIHZhcmlhYmxlcyBpbiBgV29ybGRgLiBBdHRyaWJ1dGUgdmFyaWFibGVzIHN1Y2ggYXMgYGdkcF9jYXBfZXN0YCwgYEhQSWAgYXJlIG51bWVyaWMuIE90aGVycyBzdWNoIGFzIGBpbmNvbWVfZ3JwYCBhcHBlYXIgdG8gYmUgZmFjdG9ycy4gDQpgaXNvX2EzYCBpcyB0aGUgc3RhbmRhcmQgdGhyZWUgbGV0dGVyIG5hbWUgZm9yIHRoZSBjb3VudHJ5LiANCg0KDQpgYGB7ciBXb3JsZF9tZXRyb190bWFwfQ0KZGF0YSgibWV0cm8iKQ0KaGVhZChtZXRybywgbiA9IDMpDQpgYGANCkhlcmUgdG9vIHdlIGhhdmUgYXR0cmlidXRlIHZhcmlhYmxlcyBmb3IgdGhlIG1ldHJvcywgYW5kIHRoZXkgc2VlbSBwcmVkb21pbmFudGx5IG51bWVyaWMuIEFnYWluIGBpc29fYTNgIGlzIHRoZSB0aHJlZSBsZXR0ZXIgbmFtZSBmb3IgdGhlIGNpdHkuDQoNCg0KYHRtYXBgIHBsb3RzIGFyZSBtYWRlIHdpdGggY29kZSBpbiAiZ3JvdXBzIjogZWFjaCBncm91cCBzdGFydHMgd2l0aCBhIGB0bV9zaGFwZSgpYCBjb21tYW5kLiANCg0KYGBge3IgTXlfU3RhdGljX1dvcmxkfQ0KdG1hcF9tb2RlKCJwbG90IikgIyBNYWtpbmcgdGhpcyBhIHN0YXRpYyBwbG90DQoNCiMgR3JvdXAgMQ0KdG1fc2hhcGUoV29ybGQpICsgIyBkYXRhc2V0ID0gV29ybGQuIA0KICAgIHRtX3BvbHlnb25zKCJIUEkiKSArICMgQ29sb3VyIHBvbHlnb25zIGJ5IEhQSSBudW1lcmljIHZhcmlhYmxlDQoNCiAgIyBOb3RlIHRoZSAiKyIgc2lnbiBjb250aW51YXRpb24NCiAgDQojIEdyb3VwIDINCnRtX3NoYXBlKG1ldHJvKSArICMgZGF0YXNldCA9IG1ldHJvDQogIHRtX2J1YmJsZXMoc2l6ZSA9ICJwb3AyMDIwIiwgDQogICAgICAgICAgICAgY29sID0gInJlZCIpIA0KIyBQbG90IGNpdGllcyBhcyBidWJibGVzDQojIFNpemUgcHJvcG9ydGlvbmFsIHRvIG51bWVyaWMgdmFyaWFibGUgYHBvcDIwMjBgDQpgYGANCg0KDQoNCmBgYHtyIE15IEludGVyYWN0aXZlIFdhdGVyIENvbG91ciBXb3JsZH0NCnRtYXBfbW9kZSgidmlldyIpICMgQ2hhbmdlIHRvIEludGVyYWN0aXZlDQoNCnRtX3NoYXBlKFdvcmxkKSArDQogICAgdG1fcG9seWdvbnMoIkhQSSIpICsNCiAgDQogIA0KdG1fc2hhcGUobWV0cm8pICsgDQogIHRtX2J1YmJsZXMoc2l6ZSA9ICJwb3AyMDIwIiwgDQogICAgICAgICAgICAgY29sID0gInJlZCIpICsNCg0KIyBMZXQncyB1c2UgV2F0ZXJDb2xvciBNYXAgdGhpcyB0aW1lISENCnRtX3RpbGVzKCJTdGFtZW4uVG9uZXJMYWJlbHMiKQ0KYGBgDQoNCiMjIFVzaW5nIGRhdGEgZnJvbSBgcm5hdHVyYWxlYXJ0aGANCg0KYGBge3Igc3BhdGlhbF9kYXRhfQ0KaW5kaWEgPC0gDQogIG5lX3N0YXRlcyhjb3VudHJ5ID0gICJpbmRpYSIsIA0KICAgICAgICAgICAgZ2VvdW5pdCA9ICJpbmRpYSIsIA0KICAgICAgICAgICAgcmV0dXJuY2xhc3MgPSAic2YiKQ0KDQppbmRpYV9uZWlnaGJvdXJzIDwtIA0KICBuZV9zdGF0ZXMoY291bnRyeSA9IChjKCJpbmRpYSIsICJzcmkgbGFua2EiLCAicGFraXN0YW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJhZmdoYW5pc3RhbiIsICJuZXBhbCIsImJhbmdsYWRlc2giKQ0KICAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgcmV0dXJuY2xhc3MgPSAic2YiKQ0KDQpgYGANCg0KDQpMZXQncyBsb29rIGF0IHRoZSBhdHRyaWJ1dGUgdmFyaWFibGUgY29sdW1ucyB0byBjb2xvdXIgb3VyIGdyYXBoIGFuZCB0byBzaGFwZSBvdXIgc3ltYm9sczoNCg0KYGBge3J9DQpuYW1lcyhpbmRpYSkNCm5hbWVzKGluZGlhX25laWdoYm91cnMpDQoNCiMgTG9vayBvbmx5IGF0IGF0dHJpYnV0ZXMNCmluZGlhICU+JSBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lIGhlYWQoKQ0KaW5kaWFfbmVpZ2hib3VycyU+JSBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lIGhlYWQoKQ0KYGBgDQoNCg0KIyMgTWFwIDENCmBgYHtyIE1hcF8xfQ0KdG1hcF9tb2RlKCJ2aWV3IikNCg0KIyBQbG90IHRoZSBOZWlnaGJvdXJzDQp0bV9zaGFwZShXb3JsZCAlPiUgZHBseXI6OmZpbHRlcihpc29fYTMgJWluJSBjKCJJTkQiLCAiQUZHIiwgIlBBSyIsICJOUEwiLCAiQkdEIiwgIkxLQSIpKSkgKw0KICB0bV9ib3JkZXJzKCkgKw0KICANCiMgUGxvdCBJbmRpYQ0KICB0bV9zaGFwZShpbmRpYSkgKw0KICB0bV9wb2x5Z29ucygibmFtZSIsbGVnZW5kLnNob3cgPSBGQUxTRSkgKw0KICANCiMgUGxvdCBOZWlnaGJvdXJzDQogIHRtX3NoYXBlKGluZGlhX25laWdoYm91cnMpICsNCiAgdG1fcG9seWdvbnMoIm5hbWUiLCBsZWdlbmQuc2hvdyA9IEZBTFNFKSArDQogIA0KIyBQbG90IHRoZSBjaXRpZXMgaW4gSW5kaWEgYWxvbmUNCiAgdG1fc2hhcGUobWV0cm8gJT4lIGRwbHlyOjpmaWx0ZXIoaXNvX2EzID09ICJJTkQiKSkgKw0KICB0bV9kb3RzKHNpemUgPSAicG9wMjAyMCIsbGVnZW5kLnNpemUuc2hvdyA9IEZBTFNFKSArDQogIHRtX2xheW91dChsZWdlbmQuc2hvdyA9IEZBTFNFKSArDQogIHRtX2NyZWRpdHMoIkdlb2dyYXBoaWNhbCBCb3VuZGFyaWVzIGFyZSBub3QgYWNjdXJhdGUiLA0KICAgICAgICAgICAgIHNpemUgPSAwLjUsDQogICAgICAgICAgICAgcG9zaXRpb24gPSAicmlnaHQiKSArDQogIHRtX2NvbXBhc3MocG9zaXRpb24gPSBjKCJyaWdodCIsICJ0b3AiKSkgKw0KICB0bV9zY2FsZV9iYXIocG9zaXRpb24gPSAibGVmdCIpICsNCiAgdG1hcF9zdHlsZSgid2F0ZXJjb2xvciIpIA0KDQojVHJ5IG90aGVyIG1hcCBzdHlsZXMNCiNjb2JhbHQgI2dyYXkgI3doaXRlICNjb2xfYmxpbmQgI2JlYXZlciAjY2xhc3NpYyAjd2F0ZXJjb2xvciAjYWxiYXRyb3NzICNidw0KDQpgYGANCg0KDQoNCg0KIyMgTWFwIDINCg0KYGBge3IgTWFwXzJ9DQp0bV9zaGFwZShpbmRpYV9uZWlnaGJvdXJzKSArIA0KICB0bV9wb2x5Z29ucygibmFtZSIpICsgDQogIA0KICB0bV9zaGFwZSggbWV0cm8gJT4lIGRwbHlyOjpmaWx0ZXIoaXNvX2EzICVpbiUgYygiSU5EIiwiUEFLIiwgIkxLQSIsICJCR0QiLCJOUEwiKSkpICsNCiAgdG1fZG90cyhzaXplID0gInBvcDIwMjAiKSArIA0KICB0bV9sYXlvdXQobGVnZW5kLnNob3cgPSBGQUxTRSkgKyAjIG5vIGVmZmVjdA0KICB0bWFwX29wdGlvbnMobWF4LmNhdGVnb3JpZXMgPSAxMCkgKyANCiAgdG1fY3JlZGl0cygiR2VvZ3JhcGhpY2FsIEJvdW5kYXJpZXMgYXJlIG5vdCBhY2N1cmF0ZSIsc2l6ZSA9IDAuNSxwb3NpdGlvbiA9ICJjZW50ZXIiKQ0KDQpgYGANCg0KYGBge3J9DQp0bWFwX21vZGUoInZpZXciKQ0KdG1fYmFzZW1hcCgiU3RhbWVuLldhdGVyY29sb3IiKSArDQogIHRtX3NoYXBlKG1ldHJvLCBiYm94ID0gIkluZGlhIikgKyANCiAgdG1fZG90cyhjb2wgPSAicmVkIiwgDQogICAgICAgICAgIyB1c2VyLWNob3NlbiBncm91cCBuYW1lIGZvciBsYXllcnMNCiAgICAgICAgICBncm91cCA9ICJNZXRyb3BvbGl0YW4gQXJlYXMiKSArDQogIHRtX3NoYXBlKFdvcmxkKSArIA0KICB0bV9ib3JkZXJzKCkgKyANCiAgdG1fdGlsZXMoc2VydmVyID0gIlN0YW1lbi5Ub25lckxhYmVscyIsIGdyb3VwID0gIkxhYmVscyIpICsgIyBBRERTIExBQkVMUyEhIQ0KICB0bV9ncmF0aWN1bGVzKCkNCg0KYGBgDQoNCg0KDQoNCiMjIFlvdXIgVHVybiAyDQoNCkNhbiB5b3UgdHJ5IHRvIGRvd25sb2FkIGEgbWFwIGFyZWEgb2YgeW91ciBob21lIHRvd24gYW5kIHBsb3QgaXQgYXMgd2UgaGF2ZSBhYm92ZT8NCg0KDQoNCg0KIyMgQWRkaW5nIG15IGZhdm91cml0ZSAiYXJlYSIgdG8gdGhlIG1hcA0KDQpXZSBjYW4gY3JlYXRlIGFyZWFzIG9mIGludGVyZXN0IGFyb3VuZCB0aGUgbWFwLiANCkZvciBhIHN0YXJ0OiB3ZSBhcmUgc2ltcGx5IGdvaW5nIHRvICp6b29tIGluKiB0byBhbiBhcmVhLCBkZWZpbmUgYSBzbWFsbCByZWN0YW5nbGUsICBhbmQgc2F5IHRoYXQgaXMgb3VyIGFyZWEgb2YgaW50ZXJlc3QuIA0KDQpUaGlzIGFyZWEgdGhlbiBuZWVkcyB0byBnbyAqKlRocm91Z2ggdGhlIExvb2tpbmcgR2xhc3MqKiBhbmQgYmVjb21lIHBhcnQgb2YgdGhlIHByb2plY3Rpb24gb2YgYGRhdF9CYCEhDQoNCldlIGNhbiB0aGVuIHRyeSBtb3JlIGNvbXBsZXggcXVlcmllcyBhbmQgcGxvdHMgYmFzZWQgb24geW91ciBmYXZvdXJpdGUgcmVzdGF1cmFudHMgZXRjLiANCg0KYGBge3Igc2hhcGVzX29uX21hcHN9DQoNCm15X2FyZWEgPC0gYmJveCAlPiUgDQogIA0KICAjIHpvb21pbmcgaW4gd2l0aGluIG91ciBib3VuZGluZyBib3ggYXJlYQ0KICBwcmV0dHltYXByOjp6b29tYmJveChmYWN0b3IgPSA4LCBvZmZzZXQgPSBjKDAsMCkpIA0KbXlfYXJlYQ0KYmJveA0KYGBgDQoNCk9LLCBgbXkgYXJlYWAgaXMgc21hbGwgYW5kIGNvbnRhaW5lZCBpbnNpZGUgbXkgYGJib3hgLiBTbyBgem9vbWJib3hgIHdvcmtzLiANCg0KTm93IHRvIGNvbnZlcnQgYG15X2FyZWFgIGludG8gYSBzcGF0aWFsIGRhdGFmcmFtZSB1c2luZyBgc2ZgIGFuZCBhZGQgaXQgdG8gdGhlIGBibHJfbWFwYCBwbG90Og0KDQpgYGB7cn0NCg0KIyBNYWtlIGEgbWF0cml4DQpteV9hcmVhX2luX2JsciA8LSBtYXRyaXgoDQogIGMoDQogIG15X2FyZWFbIngiLCAibWluIl0sDQogIG15X2FyZWFbIngiLCAibWF4Il0sDQogIG15X2FyZWFbIngiLCAibWF4Il0sDQogIG15X2FyZWFbIngiLCAibWluIl0sDQogIG15X2FyZWFbIngiLCAibWluIl0sDQogIG15X2FyZWFbInkiLCAibWluIl0sDQogIG15X2FyZWFbInkiLCAibWluIl0sDQogIG15X2FyZWFbInkiLCAibWF4Il0sDQogIG15X2FyZWFbInkiLCAibWF4Il0sDQogIG15X2FyZWFbInkiLCAibWluIl0pLA0KICBuY29sID0gMikgDQpteV9hcmVhX2luX2Jscg0KYGBgDQpOb3RlIHRoZSBBLUItQy1ELUEgc3RydWN0dXJlIG9mIHNwZWNpZnlpbmcgYW4gZW5jbG9zZWQgYXJlYS4gTGFzdCB2ZXJ0ZXggaXMgdGhlIHNhbWUgYXMgc3RhcnQgdmVydGV4Lg0KDQoNCmBgYHtyfQ0KIyBDb252ZXJ0IHRvIGxpc3Qgc2luY2UgUE9MWUdPTiBuZWVkcyBhIGxpc3QNCm15X2FyZWFfaW5fYmxyIDwtIA0KICANCiAgbXlfYXJlYV9pbl9ibHIgJT4lIA0KICBsaXN0KCkgJT4lIA0KDQojIENvbnZlcnQgdG8gUE9MWUdPTg0KICBzdF9wb2x5Z29uKCkgJT4lIA0KICANCiMgQ29udmVydCBQT0xZR09OIHRvIGFuIGBzZmNgIGNvbHVtbg0KIyBUaHJvdWdoIHRoZSBMb29raW5nIEdsYXNzIHdpdGggZGF0X0INCiAgc3Rfc2ZjKC4sIGNycyA9IHN0X2NycyhkYXRfQikpICU+JSANCiAgDQogICMgQ29udmVydCBzZmMgdG8gYW4gc2Ygc3BhdGlhbCBkYXRhZnJhbWUuIFBoZXchIQ0KICBzdF9hc19zZiguKSANCiAgDQoNCg0KbXlfYXJlYV9pbl9ibHINCmBgYA0KDQoNCmBgYHtyIE15X0Jscl9maW5hbGx5fQ0KYmxyX21hcCA8LSANCiAgYmxyX21hcCArIGdlb21fc2YoZGF0YSA9IG15X2FyZWFfaW5fYmxyLCBjb2xvdXIgPSAicmVkIikNCmJscl9tYXANCg0KYGBgDQoNCldlIGNvdWxkIGhhdmUgY3JlYXRlZCBhbiAqKmFyYml0cmFyeSoqIGFyZWEgb24gb3VyIG1hcCBpbiB0aGlzIHdheSwgc3RhcnRpbmcgd2l0aCBhIG1hdHJpeCBhbmQgbWFraW5nIGEgc3BhdGlhbCBkYXRhIGZyYW1lLCBhbmQgb3Zlci1wbG90dGluZyBpdCBhcyBhIGxheWVyIG9uIHRoZSBiYXNlIG1hcC4NCg0KV2UgY291bGQgYWxzbyBhZGQgKiptdWx0aXBsZSBhcmVhcyBvZiBpbnRlcmVzdCoqIHVzaW5nIC4uLnllcyBNVUxUSVBPTFlHT05zICEhDQoNCiMjIFlvdXIgVHVybiAzDQoNClRyeSBhZGRpbmcgbW9yZSB0aGFuIG9uZSAiYXJlYXMgb2YgaW50ZXJlc3QiIHRvIHlvdXIgbWFwLiANCg0KDQojIyBBZGRpbmcgbXkgZmF2b3VyaXRlIFJlc3RhdXJhbnRzIHRvIHRoZSBtYXANCklzIGl0IHRpbWUgdG8gb3JkZXIgb24gU3dpZ2d5Li4uDQoNCkxldCB1cyBhZGRpbmcgaW50ZXJlc3RpbmcgcGxhY2VzIHRvIG91ciBtYXA6IHNheSBiYXNlZCBvbiB5b3VyIGZhdm91cml0ZSByZXN0YXVyYW50cyBldGMuIFdlIG5lZWQgcmVzdGF1cmFudCBkYXRhOiBsYXQvbG9uZyArIG5hbWUgKyBtYXliZSB0eXBlIG9mIHJlc3RhdXJhbnQuIFRoaXMgY2FuIGJlIG1hbnVhbGx5IGNyZWF0ZWQgKCBsaWtlIGFsbCBvZiBPU01kYXRhICkgb3IgaWYgaXQgaXMgYWxyZWFkeSB0aGVyZSB3ZSBjYW4gZG93bmxvYWQgdXNpbmcgKmtleS12YWx1ZSogcGFpcnMgaW4gb3VyIE9TTSBkYXRhIHF1ZXJ5Lg0KDQpgYGB7ciByZXN0YXVyYW50X2RhdGFfMX0NCmRhdF9SIDwtIGV4dHJhY3Rfb3NtX29iamVjdHMoYmJveCA9IGJib3gsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSAiYW1lbml0eSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICJyZXN0YXVyYW50IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl90eXBlID0gInBvaW50IikgIzw8DQpgYGANCg0KTm90ZSB0aGUgYHJldHVybl90eXBlYCBwYXJhbWV0ZXI6IHdlIHdhbnQgdGhlIGxvY2F0aW9uIGFuZCAqKm5vdCoqIHRoZSAqKmJ1aWxkaW5nKiogaW4gd2hpY2ggdGhlIHJlc3RhdXJhbnQgaXMhIQ0KDQoNCmBgYHtyIHJlc3RhdXJhbnRfZGF0YV8yfQ0KIyBIb3cgbWFueSByZXN0YXVyYW50cyBoYXZlIHdlIGdvdD8NCmRhdF9SICU+JSBucm93KCkNCmBgYA0KDQpgYGB7ciByZXN0YXVyYW50X2RhdGFfM30NCm5hbWVzKGRhdF9SKQ0KDQpgYGANCg0KDQpgYGB7ciByZXN0YXVyYW50X2RhdGFfNH0NCiMgTGV0J3MgbG9vayBhdCB0aGUgYGN1aXNpbmVgIGNvbHVtbiEgDQojICggSSB3YW50IHBpenphLi4uKQ0KZGF0X1IkY3Vpc2luZQ0KYGBgDQoNClNvIGxldCB1cyBwbG90IHRoZSByZXN0YXVyYW50cyBhcyBQT0lOVHMgdXNpbmcgdGhlIGBkYXQtUmAgZGF0YSB3ZSBoYXZlIGRvd25sb2FkZWQuIFRoZSBgY3Vpc2luZWAgYXR0cmlidXRlIGxvb2tzIGludGVyZXN0aW5nOyBsZXQgdXMgY29sb3VyIHRoZSBQT0lOVCBiYXNlZCBvbiB0aGUgYGN1aXNpbmVgIG9mZmVyZWQgYXQgdGhhdCByZXN0YXVyYW50LiANCg0KPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtc3VjY2VzcyI+DQogIDxkaXYgY2xhc3M9InBhbmVsLWhlYWRpbmciPlRoZSBgY3Vpc2luZWAgYXR0cmlidXRlOjwvZGl2Pg0KICA8ZGl2IGNsYXNzPSJwYW5lbC1ib2R5Ij4NCk5vdGU6IFRoZSBgY3Vpc2luZWAgdmFyaWFibGUgaGFzIG1vcmUgdGhhbiBvbmUgZW50cnkgZm9yIGEgZ2l2ZW4gcmVzdGF1cmFudC4gIFdlIHVzZSBgdGlkeXI6OnNlcGFyYXRlKClgIHRvIG1ha2UgbXVsdGlwbGUgY29sdW1ucyBvdXQgb2YgdGhlIGN1aXNpbmUgY29sdW1uIGFuZCByZXRhaW4gdGhlIGZpcnN0IG9uZSBvbmx5LiBTaW5jZSB0aGUgZW50cmllcyBhcmUgYmFkbHkgZW50ZXJlZCB1c2luZyBib3RoICI7IiBhbmQgIiwiIHdlIG5lZWQgdG8gZG8gdGhpcyB0d2ljZSA7LSgpDQogIDwvZGl2Pg0KPC9kaXY+DQoNCmBgYHtyfQ0KZGF0X1IgPC0gZGF0X1IgJT4lIA0KICBkcm9wX25hKGN1aXNpbmUpICU+JSAjIEtub2NrIG9mZiBub25kZXNjcmlwdCByZXN0YXVyYW50cw0KICANCiAgIyBTb21lIGhhdmUgbW9yZSB0aGFuIG9uIGNsYXNzaWZpY2F0aW9uIDstKCkNCiAgIyBTZXBhcmF0ZWQgYnkgc2VtaWNvbG9uIG9yIGNvbW1hLCBzby4uLi4NCiAgc2VwYXJhdGUoY29sID0gY3Vpc2luZSwgaW50byA9IGMoImN1aXNpbmUiLCBOQSwgTkEpLCBzZXAgPSAiOyIpICU+JSANCiAgc2VwYXJhdGUoY29sID0gY3Vpc2luZSwgaW50byA9IGMoImN1aXNpbmUiLCBOQSwgTkEpLCBzZXAgPSAiLCIpDQoNCiMgRmluYWxseSBnb29kIGZvb2Q/DQpkYXRfUiRjdWlzaW5lDQpgYGANCg0KTm93IGxldCdzIHBsb3QgdGhlIFJlc3RhdXJhbnRzIGFzIFBPSU5UczoNCg0KYGBge3J9DQojIGh0dHA6Ly93d3cuc3RhdC5jb2x1bWJpYS5lZHUvfnR6aGVuZy9maWxlcy9SY29sb3IucGRmDQojIA0KZ2dwbG90KCkgKyANCiAgZ2VvbV9zZihkYXRhID0gZGF0X0IsIGNvbG91ciA9ICJidXJseXdvb2QxIikgKyANCiAgZ2VvbV9zZihkYXRhID0gZGF0X0gsIGNvbG91ciA9ICJncmF5ODAiKSArDQogIGdlb21fc2YoZGF0YSA9IGRhdF9SICU+JSBkcm9wX25hKGN1aXNpbmUpLCBhZXMoZmlsbCA9IGN1aXNpbmUpLCBjb2xvdXIgPSAiYmxhY2siLCBzaGFwZSA9IDIxKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArDQogIGxhYnModGl0bGUgPSAiUmVzdGF1cmFudHMgaW4gU291dGggQ2VudHJhbCBCYW5nYWxvcmUiLA0KICAgICAgIGNhcHRpb24gPSAiQmFzZWQgb24gb3NtZGF0YSIpDQpgYGANCg0KDQpXZSBjb3VsZCBoYXZlIGRvbmUgYSAobXVjaCEpIGJldHRlciBqb2IsIGJ5IGNvbWJpbmluZyBjdWlzaW5lcyBpbnRvIHNpbXBsZXIgYW5kIGZld2VyIGNhdGVnb3JpZXMsIGJ1dCB0aGF0IGlzIGZvciBhbm90aGVyIGRheSEhIA0KDQpCeSBub3cgd2Uga25vdyB0aGF0IHdlIGNhbiB1c2UgYGdlb21fc2YoKWAgbXVsdGlwbGUgbnVtYmVyIG9mIHRpbWVzIHdpdGggZGlmZmVyZW50IGRhdGFzZXRzIHRvIGNyZWF0ZSBsYXllcmVkIG1hcHMgaW4gUi4NCg0KDQoNCiMgU2NvcGUgYW5kIFBhY2thZ2VzIGZvciBFeHBsb3JhdGlvbiEhDQoNCiMjIyBzZm5ldHdvcmtzDQojIyMgbWFwc2YNCiMjIyBnZ3NwYXRpYWwNCg0KDQojIFJlc291cmNlcw0KDQoxLiBFbWluZSBGaWRhbiwgW0d1aWRlIHRvIENyZWF0aW5nIEludGVyYWN0aXZlIE1hcHMgaW4gUl0oaHR0cHM6Ly9ib29rZG93bi5vcmcvZW5lbWluZWYvRFJSX0Jvb2tkb3duLykNCg0KMi4gTmlraXRhIFZvZXZvZGluLFtSLCBOb3QgdGhlIEJlc3QgUHJhY3RpY2VzXShodHRwczovL2Jvb2tkb3duLm9yZy92b2V2b2Rpbl9udi9SX05vdF90aGVfQmVzdF9QcmFjdGljZXMvbWFwcy5odG1sKQ0KDQoNCiMgQXNzaWdubWVudHMNCg0KMS4gV2hhdCBpZiB3ZSBoYXZlIG1hcmtlZCBvdXIgZmF2b3VyaXRlIGxvY2F0aW9ucyBvbiBvdXIgc21hcnRwaG9uZXMsIHVzaW5nIEdQUz8gVW1tLi4uT0sgaGF2ZSB0byBtYWtlIG91ciBzZjpTcGF0aWFsIERhdGEgRnJhbWUgdXNpbmcgdGhlc2UgY29vcmRpbmF0ZXMuIA0KV2Ugd2lsbCBuZWVkIHRvIGRvIHRoaXMgaW4gdGhlIHNhbWUgd2F5Og0KLSBDcmVhdGUgYSBtYXRyaXgNCi0gTWFrZSBQT0lOVHMNCi0gTWFrZSBhbiBzZmMNCi0gQ29udmVydCB0byBzZg0KLSBQcm9qZWN0IGluIHRoZSBzYW1lIHdheS4gDQoNCjIuIERyYXcgYSBtYXAgb2YgeW91ciBob21lLXRvd24gd2l0aCB5b3VyIGZhdm91cml0ZSByZXN0YXVyYW50cyBzaG93bi4gUG9wLXVwcyBmb3IgZWFjaCByZXN0YXVyYW50IHdpbGwgd2luIGJvbnVzIHBvaW50cy4gDQoNCiMgSW5zcGlyYXRpb24NCg0KMS4gQnVya2hhcnQsIENocmlzdGlhbi4gbi5kLiDigJxTdHJlZXRtYXBzLuKAnSBbU3RyZWV0TWFwc10oaHR0cHM6Ly9nZ3Bsb3QydHV0b3IuY29tL3R1dG9yaWFscy9zdHJlZXRtYXBzKQ0KDQohW10oaHR0cHM6Ly9nZ3Bsb3QydHV0b3IuY29tL3N0YXRpYy8wOTM0NjZhMGY5NGYwNGYzNmUyYzAyOGZlN2FlM2YyMy9mZDg0ZS9tYXBzLnBuZykNCg0KMi4gKk1ha2luZyBWZWN0b3IgTWFwcyosIENvbXB1dGluZyBmb3IgdGhlIFNvY2lhbCBTY2llbmNlcywgW1VuaXYuIG9mIENoaWNhZ29dKGh0dHBzOi8vY2Zzcy51Y2hpY2Fnby5lZHUvbm90ZXMvdmVjdG9yLW1hcHMvKQ0K